/*
 * @Author: shawnxiao
 * @Date: 2021-08-24 14:57:54
 * @LastEditTime: 2021-08-24 15:03:43
 * @FilePath: /react-ts-pages/src/components/DynamicFormReader/FormField/DebounceSelect.tsx
 */

import React from 'react'
import { Select, Spin } from 'antd'
import { SelectProps } from 'antd/es/select'
import {debounce} from '@/common/utils'

export interface DebounceSelectProps<ValueType = any>
  extends Omit<SelectProps<ValueType>, 'options' | 'children'> {
  fetchOptions: (search: string) => Promise<ValueType[]>;
  debounceTimeout?: number;
  options?: ValueType[];
  value?: any;
  labelInValue?: boolean;
  allowClear?: boolean;
  showSearch?: boolean;
  onChange?: (v:any) => void;
}

export function DebounceSelect<
  ValueType extends { key?: string; label: React.ReactNode; value: string | number } = any
>({ fetchOptions, debounceTimeout = 800, ...props }: DebounceSelectProps) {
  const [fetching, setFetching] = React.useState(false)
  const [options, setOptions] = React.useState<ValueType[]>([...props?.options as ValueType[]])
  const fetchRef = React.useRef(0)

  const debounceFetcher = React.useMemo(() => {
    const loadOptions = (value: string) => {
      fetchRef.current += 1
      const fetchId = fetchRef.current
      setOptions([])
      setFetching(true)

      fetchOptions(value).then(newOptions => {
        if (fetchId !== fetchRef.current) {
          // for fetch callback order
          return
        }
        setOptions(newOptions)
        setFetching(false)
      })
    }
    return debounce(loadOptions, debounceTimeout)
  }, [fetchOptions, debounceTimeout])

  return (
    <Select<ValueType>
      labelInValue
      filterOption={false}
      onSearch={debounceFetcher}
      notFoundContent={fetching ? <Spin size="small" /> : '暂无数据'}
      {...props}
      options={options}
    />
  )
}
